k8s数据持久化

您所在的位置:网站首页 k8s 持久化 k8s数据持久化

k8s数据持久化

2023-11-05 14:12| 来源: 网络整理| 查看: 265

k8s数据持久化

Docker容器是有生命周期的,因此数据卷可以实现数据持久化

数据卷主要解决的问题:

数据持久性:当我们写入数据时,文件都是暂时性的存在,当容器崩溃后,host就会将这个容器杀死,然后重新从镜像创建容器,数据就会丢失数据共享:在同一个Pod中运行容器,会存在共享文件的需求 Volume:

emptyDir(空目录):使用情况比较少,一般只做临时使用,类似Docker数据 持久化的:docker manager volume,该数据卷初始分配时,是一个空目录,同一个Pod中的容器可以对该目录有执行读写操作,并且共享数据

​ 使用场景:在同一个Pod里,不同的容器,共享数据卷

​ 如果容器被删除,数据仍然存在,如果Pod被删除,数据也会被删除

使用实例:

[root@master ~]# vim emptyDir.yaml apiVersion: v1 kind: Pod metadata: name: producer-consumer spec: containers: - image: busybox name: producer volumeMounts: - mountPath: /producer_dir //容器内的路径 name: shared-volume //指定本地的目录名 args: - /bin/sh - -c - echo "hello k8s" > /producer_dir/hello; sleep 30000 - image: busybox name: consumer volumeMounts: - mountPath: /consumer_dir name: shared-volume args: - /bin/sh - -c - cat /consumer_dir/hello; sleep 30000 volumes: - name: shared-volume //这里的名字必须与上面的Pod的mountPath的name相对应 emptyDir: {} //定义数据持久化类型,即表示空目录 [root@master ~]# kubectl apply -f emptyDir.yaml [root@master ~]# kubectl get pod NAME READY STATUS RESTARTS AGE producer-consumer 2/2 Running 0 14s [root@master ~]# kubectl logs producer-consumer consumer hello k8s

使用inspect查看挂载的目录在哪(查看Mount字段)

[root@master ~]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES producer-consumer 2/2 Running 0 69s 10.244.1.2 node01 //可以看到容器运行在node01上,在node01上找到这个容器并查看并查看详细信息 [root@node01 ~]# docker ps CONTAINER ID IMAGE f117beb235cf busybox 13c7a18109a1 busybox [root@node01 ~]# docker inspect 13c7a18109a1 "Mounts": [ { "Type": "bind", "Source": "/var/lib/kubelet/pods/5225f542-0859-4a6a-8d99-1f23b9781807/volumes/kubernetes.io~empty-dir/shared-volume", "Destination": "/producer_dir", //容器内的挂载目录 "Mode": "", "RW": true, "Propagation": "rprivate" //再查看另一个容器 [root@node01 ~]# docker inspect f117beb235cf "Mounts": [ { "Type": "bind", "Source": "/var/lib/kubelet/pods/5225f542-0859-4a6a-8d99-1f23b9781807/volumes/kubernetes.io~empty-dir/shared-volume", "Destination": "/consumer_dir", //容器内的挂载目录 "Mode": "", "RW": true, "Propagation": "rprivate" //可以看到两个容器使用的同一个挂载目录 [root@node01 ~]# cd /var/lib/kubelet/pods/5225f542-0859-4a6a-8d99-1f23b9781807/volumes/kubernetes.io~empty-dir/shared-volume [root@node01 shared-volume]# ls hello [root@node01 shared-volume]# cat hello hello k8s

将容器删除,验证目录是否存在

[root@node01 ~]# docker rm -f 13c7a18109a1 13c7a18109a1 [root@node01 ~]# docker ps CONTAINER ID IMAGE a809717b1aa5 busybox f117beb235cf busybox //它会重新生成一个新的容器,来达到我们用户所期望的状态,所以这个目录还是存在的

删除Pod

[root@master ~]# kubectl delete pod producer-consumer [root@master ~]# ls /var/lib/kubelet/pods/5225f542-0859-4a6a-8d99-1f23b9781807/volumes/kubernetes.io~empty-dir/shared-volume ls: 无法访问/var/lib/kubelet/pods/5225f542-0859-4a6a-8d99-1f23b9781807/volumes/kubernetes.io~empty-dir/shared-volume: 没有那个文件或目录 //Pod删除后数据也会被删除

hostPath Volume(使用场景也比较少):类似Docker数据持久化的:bind mount

将Pod所在节点的文件系统上某一个文件或目录挂载进容器内

​ 如果Pod被删除,数据会保留,相比较emptyDir会好一点,不过,一旦host崩溃,hostPath也无法访问

docker或者k8s集群本身的存储会采用hostPath这种方式

k8s集群中会有很多pod,如果都是用hostPath Volume的话管理起来很不方便,所以就用到了PV

Persistent Volume | PV(持久卷)提前做好的,数据持久化的数据存放目录

是集群中的一块存储空间,由集群管理员管理或者由Storage class(存储类)自动管理,PV和pod、deployment、Service一样,都是一个资源对象

PersistentVolume(PV)是集群中已由管理员配置的一段网络存储。 集群中的资源就像一个节点是一个集群资源。 PV是诸如卷之类的卷插件,但是具有独立于使用PV的任何单个pod的生命周期。 该API对象捕获存储的实现细节,即NFS,iSCSI或云提供商特定的存储系统

Psesistent Volume Claim | PVC(持久卷使用声明|申请)

PVC代表用户使用存储的请求,应用申请PV持久化空间的一个申请、声明。K8s集群可能会有多个PV,你需要不停的为不同的应用创建多个PV

它类似于pod。Pod消耗节点资源,PVC消耗存储资源。 pod可以请求特定级别的资源(CPU和内存)。 权限要求可以请求特定的大小和访问模式

更多可以参考:https://www.kubernetes.org.cn/pvpvcstorageclass

基于NFS服务来做的PV

[root@master ~]# yum -y install nfs-utils (需要节点全部下载,会报挂载类型错误) [root@master ~]# yum -y install rpcbind [root@master ~]# mkdir /nfsdata [root@master ~]# vim /etc/exports /nfsdata *(rw,sync,no_root_squash) [root@master ~]# systemctl start rpcbind [root@master ~]# systemctl start nfs-server [root@master ~]# showmount -e Export list for master: /nfsdata *

1.创建PV(实际的存储目录) 2.创建PVC 3.创建pod

创建PV资源对象:

[root@master ~]# vim nfs-pv.yaml apiVersion: v1 kind: PersistentVolume metadata: name: test-pv spec: capacity: //PV容量的大小 storage: 1Gi accessModes: //PV支持的访问模式 - ReadWriteOnce persistentVolumeReclaimPolicy: Recycle //PV的存储空间的回收策略是什么 storageClassName: nfs nfs: path: /nfsdata/pv1 server: 192.168.1.70 [root@master ~]# kubectl apply -f nfs-pv.yaml [root@master ~]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE test-pv 1Gi RWO Recycle Available nfs 9m30s

accessModes: (PV支持的访问模式)

​ - ReadWriteOnce:能以读-写的方式mount到单个节点

​ - ReadWriteMany:能以读-写的方式mount到多个节点

​ - ReadOnlyMany:能以只读的方式mount到单个节点

persistentVolumeReclaimPolicy:(PV的存储空间的回收策略是什么)

​ Recycle:自动清除数据

​ Retain:需要管理员手动回收

​ Delete:云存储专用。直接删除数据

PV和PVC相互的关联:通过的是storageClassName && accessModes

创建PVC

[root@master ~]# vim nfs-pvc.yaml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: test-pvc spec: accessModes: //访问模式 - ReadWriteOnce resources: requests: storage: 1Gi //申请的容量大小 storageClassName: nfs //向哪个PV申请 [root@master ~]# kubectl apply -f nfs-pvc.yaml [root@master ~]# kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE test-pvc Bound test-pv 1Gi RWO nfs 14s PV的应用:

创建一个Pod资源:

[root@master ~]# vim pod.yaml kind: Pod apiVersion: v1 metadata: name: test-pod spec: containers: - name: pod1 image: busybox args: - /bin/sh - -c - sleep 30000 volumeMounts: - mountPath: "/mydata" name: mydata volumes: - name: mydata persistentVolumeClaim: claimName: test-pvc [root@master ~]# kubectl apply -f pod.yaml

之前创建PV的时候指定的挂载目录是/nfsdata/pv1,我们并没有创建pv1这个目录,所以这个pod是运行不成功的。

以下是排错方法:

kubectl describekubectl logs/var/log/messages查看该节点的kubelet的日志 //使用kubectl describe [root@master ~]# kubectl describe pod test-pod mount.nfs: mounting 192.168.1.70:/nfsdata/pv1 failed, reason given by server: No such file or directory //提示没有文件或目录

创建目录,再查看pod状态:

[root@master ~]# mkdir /nfsdata/pv1 NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES test-pod 1/1 Running 0 12m 10.244.1.3 node01

验证是否应用成功:

[root@master ~]# kubectl exec test-pod touch /mydata/hello [root@master ~]# ls /nfsdata/pv1/ hello [root@master ~]# echo 123 > /nfsdata/pv1/hello [root@master ~]# kubectl exec test-pod cat /mydata/hello 123

删除Pod,验证回收策略(Recycle):

[root@master ~]# kubectl delete pod test-pod [root@master ~]# kubectl delete pvc test-pvc [root@master ~]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE test-pv 1Gi RWO Recycle Available nfs 42h [root@master ~]# ls /nfsdata/pv1/ [root@master ~]# //验证成功,数据已经回收

通常情况下不会设置为自动删除,不然就和emptyDir就差不多了

删除pv,修改回收策略:

之前是先创建PV—>PVC—>Pod,现在调整一下,先创建PV—>---Pod—>PVC

[root@master ~]# vim nfs-pv.yaml persistentVolumeReclaimPolicy: Retain [root@master ~]# kubectl apply -f nfs-pv.yaml [root@master ~]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE test-pv 1Gi RWO Retain Available nfs 7s [root@master ~]# kubectl apply -f pod.yaml [root@master ~]# kubectl get pod NAME READY STATUS RESTARTS AGE test-pod 0/1 Pending 0 5s //Pending正在被调度 [root@master ~]# kubectl describe pod test-pod Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning FailedScheduling 41s (x2 over 41s) default-scheduler persistentvolumeclaim "test-pvc" not found //没有发现对应的pvc 创建pvc [root@master ~]# kubectl apply -f nfs-pvc.yaml [root@master ~]# kubectl get pod NAME READY STATUS RESTARTS AGE test-pod 1/1 Running 0 114s

验证Retain(管理员手动删除)回收策略:

[root@master ~]# kubectl exec test-pod touch /mydata/k8s [root@master ~]# ls /nfsdata/pv1/ k8s [root@master ~]# kubectl delete pod test-pod [root@master ~]# kubectl delete pvc test-pvc [root@master ~]# ls /nfsdata/pv1/ k8s //可以看到并没有回收 [root@master ~]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE test-pv 1Gi RWO Retain Available nfs 6s

mysql对数据持久化的应用:

//这里就不再创建PV,PVC了,用之前的就行

[root@master ~]# kubectl apply -f nfs-pvc.yaml [root@master ~]# kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE test-pvc Bound test-pv 1Gi RWO nfs 7s

创建Deploment资源对象,mysql容器

[root@master ~]# vim mysql.yaml apiVersion: extensions/v1beta1 kind: Deployment metadata: name: test-mysql spec: selector: matchLabels: //基于等值的标签 app: mysql template: metadata: labels: app: mysql spec: containers: - image: mysql:5.6 name: mysql env: - name: MYSQL_ROOT_PASSWORD value: 123.com volumeMounts: - name: mysql-storage mountPath: /var/lib/mysql volumes: - name: mysql-storage persistentVolumeClaim: claimName: test-pvc [root@master ~]# kubectl get deployments. NAME READY UP-TO-DATE AVAILABLE AGE test-mysql 1/1 1 1 61s

进入容器创建数据,验证是否应用PV:

[root@master ~]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES test-mysql-569f8df4db-fnnxc 1/1 Running 0 32m 10.244.1.5 node01 [root@master ~]# kubectl exec -it test-mysql-569f8df4db-fnnxc -- mysql -u root -p123.com mysql> create database yun33; //创建数据库 mysql> use yun33; //选择使用数据路 Database changed mysql> create table my_id( id int(4)); 创建表 mysql> insert my_id values(9527); //在表中插入数据 mysql> select * from my_id; //查看表中所有数据 +------+ | id | +------+ | 9527 | +------+ 1 row in set (0.00 sec) [root@master ~]# ls /nfsdata/pv1/ auto.cnf ibdata1 ib_logfile0 ib_logfile1 k8s mysql performance_schema yun33

关闭node01节点,模拟节点宕机:

[root@master ~]# kubectl get nodes NAME STATUS ROLES AGE VERSION master Ready master 36d v1.15.0 node01 NotReady 36d v1.15.0 node02 Ready 36d v1.15.0 [root@master ~]# kubectl get pod -o wide -w NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES test-mysql-569f8df4db-fnnxc 1/1 Running 0 36m 10.244.1.5 node01 test-mysql-569f8df4db-fnnxc 1/1 Terminating 0 38m 10.244.1.5 node01 test-mysql-569f8df4db-2m5rd 0/1 Pending 0 0s test-mysql-569f8df4db-2m5rd 0/1 Pending 0 0s node02 test-mysql-569f8df4db-2m5rd 0/1 ContainerCreating 0 0s node02 test-mysql-569f8df4db-2m5rd 1/1 Running 0 2s 10.244.2.4 node02 [root@master ~]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES test-mysql-569f8df4db-2m5rd 1/1 Running 0 20s 10.244.2.4 node02 test-mysql-569f8df4db-fnnxc 1/1 Terminating 0 38m 10.244.1.5 node01

验证:在node02上新生成的pod,它内部是否有我们创建的数据

[root@master ~]# kubectl exec -it test-mysql-569f8df4db-2m5rd -- mysql -u root -p123.com mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | yun33 | +--------------------+ 4 rows in set (0.01 sec) mysql> use yun33; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> show tables; +-----------------+ | Tables_in_yun33 | +-----------------+ | my_id | +-----------------+ 1 row in set (0.01 sec) mysql> select * from my_id; +------+ | id | +------+ | 9527 | +------+ 1 row in set (0.01 sec) [root@master ~]# ls /nfsdata/pv1/ auto.cnf ibdata1 ib_logfile0 ib_logfile1 k8s mysql performance_schema yun33

Pod不断的重启:

​ 1.swap,没有关闭。导致集群运行不正常

​ 2.内存不足,运行服务也会重启

小结

负责把PVC绑定到PV的是一个持久化存储卷控制循环,这个控制器也是kube-manager-controller的一部分运行在master上。而真正把目录挂载到容器上的操作是在POD所在主机上发生的,所以通过kubelet来完成。而且创建PV以及PVC的绑定是在POD被调度到某一节点之后进行的,完成这些操作,POD就可以运行了。下面梳理一下挂载一个PV的过程:

用户提交一个包含PVC的POD调度器把根据各种调度算法把该POD分配到某个节点,比如node01Node01上的kubelet等待Volume Manager准备存储设备PV控制器调用存储插件创建PV并与PVC进行绑定Attach/Detach Controller或Volume Manager通过存储插件实现设备的attach。(这一步是针对块设备存储)Volume Manager等待存储设备变为可用后,挂载该设备到/var/lib/kubelet/pods//volumes/kubernetes.io~/目录上Kubelet被告知卷已经准备好,开始启动POD,通过映射方式挂载到容器中


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3